// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#ifndef MGCTERRAINPAGE_H
#define MGCTERRAINPAGE_H

#include "MgcTriMesh.h"
class MgcCamera;
class MgcTerrainBlock;
class MgcTerrainVertex;


class MgcTerrainPage : public MgcTriMesh
{
    MgcDeclareRTTI;
    MgcDeclareStream;

public:
    // size = 2^p + 1, p <= 7 (size = 3, 5, 9, 17, 33, 65, 129)
    MgcTerrainPage (unsigned short usSize, unsigned short* ausHeight,
        const MgcVector2& rkOrigin, MgcReal fMinElevation,
        MgcReal fMaxElevation, MgcReal fSpacing);

    virtual ~MgcTerrainPage ();

    // height field access
    unsigned short GetSize () const;
    const unsigned short* GetHeights () const;
    const MgcVector2& GetOrigin () const;
    MgcReal GetMinElevation () const;
    MgcReal GetMaxElevation () const;
    MgcReal GetSpacing () const;

    // pixel tolerance on projected vertex height
    void SetPixelTolerance (long lWidth, MgcCamera* pkCamera, MgcReal fTolerance);
    MgcReal GetPixelTolerance () const;

    // Height field measurements.  If the location is not in the page, the
    // return value is INFINITY.
    MgcReal GetHeight (const MgcVector2& rkLocation) const;

    // simplification
    void ResetBlocks ();
    void Simplify (long lWidth, MgcCamera* pkCamera, const MgcVector3& rkModelEye,
        const MgcVector3& rkModelDir, bool bCloseAssumption);
	void Draw (); // for DXUT

protected:
    friend MgcTerrainBlock;

    // streaming support
    MgcTerrainPage ();
    void InitializeDerivedData ();

    // queue handlers
    void AddToQueue (unsigned short usBlock);
    unsigned short RemoveFromQueue ();
    unsigned short ReadFromQueue (unsigned short usIndex);

    // page simplification
    bool IntersectFrustum (const MgcCamera* pkCamera);

    // block simplification
    void SimplifyBlocks (const MgcCamera* pCamera,
        const MgcVector3& rkModelEye, const MgcVector3& rkModelDir,
        bool bCloseAssumption);

    // vertex simplification
    void SimplifyVertices (const MgcVector3& rkModelEye,
        const MgcVector3& rkModelDir, bool bCloseTerrainAssumption);

    // tessellation
    MgcReal GetX (unsigned char ucX) const;
    MgcReal GetY (unsigned char ucY) const;
    MgcReal GetHeight (unsigned short usIndex) const;
    MgcReal GetTexture (unsigned char ucIndex) const;
    void Render (MgcTerrainBlock& rkBlock);
    void RenderTriangle (unsigned short usT, unsigned short usL,
        unsigned short usR);
    void RenderBlocks ();

    virtual void Draw (MgcRenderer& rkRenderer);

    // for multiple pages in the terrain system
    void StitchLR (MgcTerrainPage* pkRight);
    void StitchTB (MgcTerrainPage* pkBottom);
    void UnstitchLR (MgcTerrainPage* pkRight);
    void UnstitchTB (MgcTerrainPage* pkBottom);

    // height field
    unsigned short m_usSize, m_usSizeM1;
    unsigned short* m_ausHeight;
    MgcVector2 m_kOrigin;
    MgcReal m_fMinElevation, m_fMaxElevation, m_fSpacing;
    MgcReal m_fInvSpacing, m_fTextureSpacing, m_fMultiplier;

    // simplification
    MgcReal m_fPixelTolerance, m_fWorldTolerance;
    bool m_bNeedsTessellation;
    unsigned short* m_ausLookup;
    unsigned int m_uiConnectLength;

    // (2^p+1) by (2^p+1) array of vertices, row-major order
    MgcTerrainVertex* m_akTVertex;

    // quadtree of blocks
    unsigned short m_usBlockQuantity;
    MgcTerrainBlock* m_akBlock;

    // circular queue of indices for active blocks
    unsigned short* m_ausQueue;
    unsigned short m_usQueueQuantity;
    unsigned short m_usFront, m_usRear;
    unsigned short m_usNumUnprocessed;
    unsigned short m_usItemsInQueue;
};

MgcSmartPointer(MgcTerrainPage);
MgcRegisterStream(MgcTerrainPage);
#include "MgcTerrainPage.inl"

#endif
